home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / proc / procServer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  15.1 KB  |  571 lines

  1. /* 
  2.  *  procServer.c --
  3.  *
  4.  *    Routines to manage pool of server processes.
  5.  *
  6.  * Copyright 1987, 1988 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/proc/procServer.c,v 9.11 92/06/01 14:41:39 kupfer Exp $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include <sprite.h>
  21. #include <mach.h>
  22. #include <proc.h>
  23. #include <procInt.h>
  24. #include <sync.h>
  25. #include <sched.h>
  26. #include <timer.h>
  27. #include <list.h>
  28. #include <vm.h>
  29. #include <fs.h>
  30. #include <fscache.h>
  31. #include <sys.h>
  32. #include <string.h>
  33. #include <status.h>
  34. #include <stdlib.h>
  35. #include <procServer.h>
  36. #include <stdio.h>
  37.  
  38. /*
  39.  * Circular queue of pending function calls.
  40.  */
  41. QueueElement    queue[NUM_QUEUE_ELEMENTS];
  42.  
  43. /*
  44.  * Indices into circular queue.  frontIndex is index of next function to call.
  45.  * nextIndex is index of where to put next call.  When frontIndex and nextIndex
  46.  * are equal then queue is full.  When frontIndex = -1 then queue is empty.
  47.  */
  48. int    frontIndex = -1;
  49. int    nextIndex = 0;
  50.  
  51. ServerInfo    *serverInfoTable = (ServerInfo *) NIL;
  52.  
  53. int    proc_NumServers = 0;
  54.  
  55. /*
  56.  * MAX_NUM_SERVER_PROCS - The maximum number of Proc_ServerProcs allowed.
  57.  */
  58. #define    MAX_NUM_SERVER_PROCS    32
  59.  
  60. /* 
  61.  * Mutex to synchronize accesses to the queue of pending requests and
  62.  * to the process state.
  63.  */
  64. Sync_Semaphore    serverMutex; 
  65.  
  66. static void     ScheduleFunc _ARGS_((void (*func)(ClientData clientData,
  67.                           Proc_CallInfo    *callInfoPtr),
  68.             ClientData clientData, unsigned int interval, 
  69.             FuncInfo *funcInfoPtr));
  70. static void     CallFuncFromTimer _ARGS_((Timer_Ticks time, 
  71.             ClientData data));
  72. static void    CallFunc _ARGS_((FuncInfo *funcInfoPtr));    
  73.  
  74. /*
  75.  *----------------------------------------------------------------------
  76.  *
  77.  * Proc_CallFunc --
  78.  *
  79.  *    Start a process that calls the given function.  The process will
  80.  *    be started after waiting for interval amount of time where interval is
  81.  *    of the form expected by the timer module (e.g. timer_IntOneSecond). 
  82.  *    Proc_CallFunc can be called with interrupts disabled as long as
  83.  *    interval is 0 (when interval is non-zero, the memory allocator is
  84.  *    called).  When func is called it will be called as 
  85.  *
  86.  *        void
  87.  *        func(clientData, callInfoPtr)
  88.  *            ClientData    clientData;
  89.  *            Proc_CallInfo    *callInfoPtr;
  90.  *
  91.  *    The callInfoPtr struct contains two fields: a client data field and
  92.  *    an interval field.  callInfoPtr->interval is initialized to 0 and
  93.  *    callInfoPtr->clientData is initialized to clientData.  If when func
  94.  *    returns the callInfoPtr->interval is non-zero then the function will
  95.  *    be scheduled to be called again after waiting the given interval.  It
  96.  *    will be passed the client data in callInfoPtr->clientData.
  97.  *
  98.  *    NOTE: There are a fixed number of processes to execute functions 
  99.  *          specified by Proc_CallFunc.  Therefore the functions given
  100.  *          to Proc_CallFunc should always return after a short period
  101.  *          of time.  Otherwise all processes will be tied up.
  102.  *          
  103.  * Results:
  104.  *    None.
  105.  *
  106.  * Side effects:
  107.  *    None.
  108.  *
  109.  *----------------------------------------------------------------------
  110.  */
  111. void
  112. Proc_CallFunc(func, clientData, interval)
  113.     void        (*func) _ARGS_((ClientData clientData, 
  114.             Proc_CallInfo    *callInfoPtr));    /* Function to call. */
  115.     ClientData        clientData;    /* Data to pass function. */
  116.     unsigned    int    interval;    /* Time to wait before calling func. */
  117. {
  118.     FuncInfo    funcInfo;
  119.  
  120.     if (interval != 0) {
  121.     ScheduleFunc(func, clientData, interval, (FuncInfo *) NIL);
  122.     } else {
  123.     funcInfo.func = func;
  124.     funcInfo.data = clientData;
  125.     funcInfo.allocated = FALSE;
  126.     CallFunc(&funcInfo);
  127.     }
  128. }
  129.  
  130. /*
  131.  *----------------------------------------------------------------------
  132.  *
  133.  * Proc_CallFuncAbsTime --
  134.  *
  135.  *    This routine is a variant of Proc_CallFunc. It starts a process
  136.  *    to call the given function at a specific time.  Proc_CallFuncAbsTime 
  137.  *    can not be called with interrupts disabled. When func is called it 
  138.  *    will be called as:
  139.  *
  140.  *        void
  141.  *        func(clientData, callInfoPtr)
  142.  *            ClientData    clientData;
  143.  *            Proc_CallInfo    *callInfoPtr;
  144.  *
  145.  *    The callInfoPtr struct must not be modified!! (it is used by
  146.  *    routines scheduled with Proc_CallFunc).    The only field of interest
  147.  *    is "token" -- it is the same value that was returned by 
  148.  *    Proc_CallFuncAbsTime when func was scheduled. Func will be called 
  149.  *    exactly once: if func needs to be resecheduled, it must call 
  150.  *    Proc_CallFuncAbsTime with a new time value.
  151.  *
  152.  *    NOTE:    There are a fixed number of processes to execute functions 
  153.  *        specified by the Proc_CallFunc* routines.  Therefore the 
  154.  *        functions given to Proc_CallFuncAbsTime should always 
  155.  *        return after a short period of time.  Otherwise all 
  156.  *        processes will be tied up.
  157.  *          
  158.  * Results:
  159.  *    A token to identify this instance of the Proc_CallFuncAbsTime call.
  160.  *    The token is passed to the func in the Proc_CallInfo struct.
  161.  *
  162.  * Side effects:
  163.  *    Memory for the FuncInfo struct is allocated.
  164.  *
  165.  *----------------------------------------------------------------------
  166.  */
  167. ClientData
  168. Proc_CallFuncAbsTime(func, clientData, time)
  169.     void        (*func) _ARGS_((ClientData clientData, 
  170.             Proc_CallInfo    *callInfoPtr));    /* Function to call. */
  171.     ClientData        clientData;    /* Data to pass to func. */
  172.     Timer_Ticks        time;        /* Time when to call func. */
  173. {
  174.     register FuncInfo    *funcInfoPtr;
  175.  
  176.     funcInfoPtr = (FuncInfo *) malloc(sizeof (FuncInfo));
  177.     funcInfoPtr->func = func;
  178.     funcInfoPtr->data = clientData;
  179.     funcInfoPtr->allocated = TRUE;
  180.     funcInfoPtr->queueElement.routine = CallFuncFromTimer;
  181.     funcInfoPtr->queueElement.clientData = (ClientData) funcInfoPtr;
  182.     funcInfoPtr->queueElement.time = time;
  183.     funcInfoPtr->queueElement.interval = 0;
  184.     Timer_ScheduleRoutine(&funcInfoPtr->queueElement, FALSE);
  185.     return((ClientData) funcInfoPtr);
  186. }
  187.  
  188.  
  189. /*
  190.  *----------------------------------------------------------------------
  191.  *
  192.  * Proc_CancelCallFunc --
  193.  *
  194.  *    This routine is used to deschedule a timer entry created by
  195.  *    Proc_CallFuncAbsTime.   
  196.  *          
  197.  * Results:
  198.  *    None.
  199.  *
  200.  * Side effects:
  201.  *    The timer entry is removed from the timer queue.
  202.  *
  203.  *----------------------------------------------------------------------
  204.  */
  205. void
  206. Proc_CancelCallFunc(token)
  207.     ClientData        token;    /* Opaque identifier for function info */
  208. {
  209.     register FuncInfo    *funcInfoPtr = (FuncInfo *) token;
  210.     Boolean removed;
  211.  
  212.     removed = Timer_DescheduleRoutine(&funcInfoPtr->queueElement);
  213.     if (removed && funcInfoPtr->allocated) {
  214.     free((Address) funcInfoPtr);
  215.     }
  216. }
  217.  
  218. /*
  219.  *----------------------------------------------------------------------
  220.  *
  221.  * Proc_ServerInit --
  222.  *
  223.  *    Initialize the state and the set of processes needed to execute
  224.  *    functions.
  225.  *
  226.  * Results:
  227.  *    None.
  228.  *
  229.  * Side effects:
  230.  *    Server info table initialized.
  231.  *
  232.  *----------------------------------------------------------------------
  233.  */
  234. void
  235. Proc_ServerInit()
  236. {
  237.     int        i;
  238.  
  239.     serverInfoTable = 
  240.      (ServerInfo *) Vm_RawAlloc(MAX_NUM_SERVER_PROCS * sizeof(ServerInfo));
  241.     for (i = 0; i < MAX_NUM_SERVER_PROCS; i++) {
  242.     serverInfoTable[i].index = i;
  243.     serverInfoTable[i].flags = 0;
  244.     serverInfoTable[i].condition.waiting = 0;
  245.     }
  246.     Sync_SemInitDynamic(&serverMutex, "Proc:serverMutex");
  247. }
  248.  
  249.  
  250. /*
  251.  *----------------------------------------------------------------------
  252.  *
  253.  * Proc_ServerProcCreate --
  254.  *
  255.  *    Create the specified number of Proc_Servers. 
  256.  *
  257.  * Results:
  258.  *    The number created.
  259.  *
  260.  * Side effects:
  261.  *    proc_NumServer increased and processes created.
  262.  *
  263.  *----------------------------------------------------------------------
  264.  */
  265. int
  266. Proc_ServerProcCreate(numToCreate)
  267.     int    numToCreate;    /* Number of procServer processes to create. */
  268. {
  269.     Proc_PID    pid;
  270.     int        i;
  271.     Boolean    maxedOut;
  272.  
  273.     if (serverInfoTable == (ServerInfo *) NIL) {
  274.     panic("Proc_ServerProcCreate called before Proc_ServerInit\n");
  275.     return 0;
  276.     }
  277.     maxedOut = FALSE;
  278.     for (i = 0; i < numToCreate; i++) { 
  279.     /*
  280.      * Until proc_NumServers is maxedOut increment it. We grab
  281.      * serverMutux to protect others against others doing the
  282.      * same.
  283.      */
  284.     MASTER_LOCK(&serverMutex);
  285.     if (proc_NumServers < MAX_NUM_SERVER_PROCS) {
  286.         proc_NumServers++;
  287.     } else {
  288.         maxedOut = TRUE;
  289.     }
  290.     MASTER_UNLOCK(&serverMutex);
  291.     if (maxedOut) {
  292.         break;
  293.     }
  294.     (void) Proc_NewProc((Address) Proc_ServerProc, PROC_KERNEL, FALSE, 
  295.             &pid, "Proc_ServerProc", FALSE);
  296.     }
  297.     return i;
  298. }
  299.  
  300.  
  301. /*
  302.  *----------------------------------------------------------------------
  303.  *
  304.  * Proc_ServerProc --
  305.  *
  306.  *    Function for a server process.
  307.  *
  308.  * Results:
  309.  *    None.
  310.  *
  311.  * Side effects:
  312.  *    None.
  313.  *
  314.  *----------------------------------------------------------------------
  315.  */
  316.  
  317. void
  318. Proc_ServerProc()
  319. {
  320.     register    ServerInfo    *serverInfoPtr;
  321.     Proc_CallInfo        callInfo;
  322.     int                i;
  323.  
  324.     MASTER_LOCK(&serverMutex);
  325.     Sync_SemRegister(&serverMutex);
  326.     /*
  327.      * Find which server table entry that we are to use.
  328.      */
  329.     for (i = 0, serverInfoPtr = serverInfoTable;
  330.      i < proc_NumServers;
  331.      i++, serverInfoPtr++) {
  332.     if (serverInfoPtr->flags == 0) {
  333.         serverInfoPtr->flags = ENTRY_INUSE;
  334.         break;
  335.     }
  336.     }
  337.     if (i == proc_NumServers) {
  338.     MASTER_UNLOCK(&serverMutex);
  339.     printf("Warning: Proc_ServerProc: No server entries free.\n");
  340.     Proc_Exit(0);
  341.     }
  342.  
  343.     Sched_SetClearUsageFlag();
  344.  
  345.     while (!sys_ShuttingDown) {
  346.     if (!(serverInfoPtr->flags & FUNC_PENDING)) {
  347.         /*
  348.          * There is nothing scheduled for us to do.  If there is something
  349.          * on the queue then dequeue it.  Otherwise sleep.
  350.          */
  351.         if (!QUEUE_EMPTY) {
  352.         serverInfoPtr->info = queue[frontIndex];
  353.         if (frontIndex == NUM_QUEUE_ELEMENTS - 1) {
  354.             frontIndex = 0;
  355.         } else {
  356.             frontIndex++;
  357.         }
  358.         if (frontIndex == nextIndex) {
  359.             frontIndex = -1;
  360.             nextIndex = 0;
  361.         }
  362.         } else {
  363.         Sync_MasterWait(&serverInfoPtr->condition,
  364.                 &serverMutex, TRUE);
  365.         continue;
  366.         }
  367.     }
  368.  
  369.     serverInfoPtr->flags |= SERVER_BUSY;
  370.     serverInfoPtr->flags &= ~FUNC_PENDING;
  371.  
  372.     MASTER_UNLOCK(&serverMutex);
  373.  
  374.     /*
  375.      * Call the function.
  376.      */
  377.     callInfo.interval = 0;
  378.     callInfo.clientData = serverInfoPtr->info.data;
  379.     callInfo.token = (ClientData) serverInfoPtr->info.funcInfoPtr;
  380.     serverInfoPtr->info.func(serverInfoPtr->info.data, &callInfo);
  381.  
  382.     if (callInfo.interval != 0) {
  383.         /* 
  384.          * It wants us to call it again.
  385.          */
  386.         ScheduleFunc(serverInfoPtr->info.func, callInfo.clientData,
  387.              callInfo.interval, serverInfoPtr->info.funcInfoPtr);
  388.     } else {
  389.         /*
  390.          * Aren't supposed to call it again.  Free up function info
  391.          * if was allocated for this function.
  392.          */
  393.         if (serverInfoPtr->info.funcInfoPtr != (FuncInfo *) NIL) {
  394.         free((Address) serverInfoPtr->info.funcInfoPtr);
  395.         }
  396.     }
  397.  
  398.     /*
  399.      * Go back around looking for something else to do.
  400.      */
  401.     MASTER_LOCK(&serverMutex);
  402.     serverInfoPtr->flags &= ~SERVER_BUSY;
  403.     }
  404.     MASTER_UNLOCK(&serverMutex);
  405.     printf("Proc_ServerProc exiting.\n");
  406. }
  407.  
  408.  
  409. /*
  410.  *----------------------------------------------------------------------
  411.  *
  412.  * ScheduleFunc --
  413.  *
  414.  *    Schedule the given function to be called at the given time.
  415.  *
  416.  * Results:
  417.  *    None.
  418.  *
  419.  * Side effects:
  420.  *    None.
  421.  *
  422.  *----------------------------------------------------------------------
  423.  */
  424.  
  425. static void
  426. ScheduleFunc(func, clientData, interval, funcInfoPtr)
  427.     void        (*func) _ARGS_((ClientData clientData, 
  428.             Proc_CallInfo    *callInfoPtr));    /* Function to call. */
  429.     ClientData        clientData;    /* Data to pass function. */
  430.     unsigned    int    interval;    /* Time to wait before calling func. */
  431.     FuncInfo        *funcInfoPtr;    /* Pointer to function information
  432.                      * structure that may already exist. */
  433. {
  434.     if (funcInfoPtr == (FuncInfo *) NIL) {
  435.     /*
  436.      * We have not allocated a structure yet for waiting.  Do it now.
  437.      */
  438.     funcInfoPtr = (FuncInfo *) malloc(sizeof (FuncInfo));
  439.     funcInfoPtr->func = func;
  440.     funcInfoPtr->data = clientData;
  441.     funcInfoPtr->allocated = TRUE;
  442.     funcInfoPtr->queueElement.routine = CallFuncFromTimer;
  443.     funcInfoPtr->queueElement.clientData = (ClientData) funcInfoPtr;
  444.     } else {
  445.     funcInfoPtr->data = clientData;
  446.     }
  447.  
  448.     /*
  449.      * Schedule the call back.
  450.      */
  451.     funcInfoPtr->queueElement.interval = interval;
  452.     Timer_ScheduleRoutine(&funcInfoPtr->queueElement, TRUE);
  453. }
  454.  
  455.  
  456. /*
  457.  *----------------------------------------------------------------------
  458.  *
  459.  * CallFuncFromTimer --
  460.  *
  461.  *    Actually schedule the calling of the function by one of the
  462.  *    server processes.
  463.  *
  464.  * Results:
  465.  *    None.
  466.  *
  467.  * Side effects:
  468.  *    Item will be enqueued if no free processes are available.  Otherwise
  469.  *    The state of one of the processes is mucked with so that it knows
  470.  *    that it has a function to executed.
  471.  *
  472.  *----------------------------------------------------------------------
  473.  */
  474.  
  475. /* ARGSUSED */
  476. static void
  477. CallFuncFromTimer(time, data)
  478.     Timer_Ticks        time;        /* Unused. */
  479.     ClientData        data;        /* FuncInfo. */
  480. {
  481.     CallFunc((FuncInfo *) data);
  482. }
  483.  
  484.  
  485. /*
  486.  *----------------------------------------------------------------------
  487.  *
  488.  * CallFunc --
  489.  *
  490.  *    Actually schedule the calling of the function by one of the
  491.  *    server processes.
  492.  *
  493.  * Results:
  494.  *    None.
  495.  *
  496.  * Side effects:
  497.  *    Item will be enqueued if no free processes are available.  Otherwise
  498.  *    The state of one of the processes is mucked with so that it knows
  499.  *    that it has a function to executed.
  500.  *
  501.  *----------------------------------------------------------------------
  502.  */
  503.  
  504. static void
  505. CallFunc(funcInfoPtr)
  506.     FuncInfo        *funcInfoPtr;
  507. {
  508.     register    ServerInfo    *serverInfoPtr;
  509.     register    QueueElement    *queueElementPtr;
  510.     Boolean            queueIt = TRUE;
  511.     int                i;
  512.  
  513.     MASTER_LOCK(&serverMutex);
  514.     if (QUEUE_EMPTY) {
  515.     /*
  516.      * If the the queue is empty then there may in fact be a
  517.      * server ready to call out function.
  518.      */
  519.     for (i = 0, serverInfoPtr = serverInfoTable;
  520.          i < proc_NumServers;
  521.          i++, serverInfoPtr++) {
  522.         if (!(serverInfoPtr->flags & ENTRY_INUSE) ||
  523.             (serverInfoPtr->flags & (SERVER_BUSY | FUNC_PENDING))) {
  524.         continue;
  525.         }
  526.         serverInfoPtr->flags |= FUNC_PENDING;
  527.         serverInfoPtr->info.func = funcInfoPtr->func;
  528.         serverInfoPtr->info.data = funcInfoPtr->data;
  529.         if (funcInfoPtr->allocated) {
  530.         serverInfoPtr->info.funcInfoPtr = funcInfoPtr;
  531.         } else {
  532.         serverInfoPtr->info.funcInfoPtr = (FuncInfo *) NIL;
  533.         }
  534.         Sync_MasterBroadcast(&serverInfoPtr->condition);
  535.         queueIt = FALSE;
  536.         break;
  537.     }
  538.     }
  539.  
  540.     if (queueIt) {
  541.     /*
  542.      * There are no free servers available so we have to queue up the
  543.      * message.
  544.      */
  545.     if (QUEUE_FULL) {
  546.         extern Boolean sys_ShouldSyncDisks;
  547.         Mach_EnableIntr();
  548.         sys_ShouldSyncDisks = FALSE;
  549.         panic("CallFunc: Process queue full.\n");
  550.     }
  551.     queueElementPtr = &queue[nextIndex];
  552.     queueElementPtr->func = funcInfoPtr->func;
  553.     queueElementPtr->data = funcInfoPtr->data;
  554.     if (funcInfoPtr->allocated) {
  555.         queueElementPtr->funcInfoPtr = funcInfoPtr;
  556.     } else {
  557.         queueElementPtr->funcInfoPtr = (FuncInfo *) NIL;
  558.     }
  559.     if (nextIndex == NUM_QUEUE_ELEMENTS - 1) {
  560.         nextIndex = 0;
  561.     } else {
  562.         nextIndex++;
  563.     }
  564.     if (frontIndex == -1) {
  565.         frontIndex = 0;
  566.     }
  567.     }
  568.  
  569.     MASTER_UNLOCK(&serverMutex);
  570. }
  571.